/*
 * Copyright 2013 Agustina Martinez-Garcia

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package uk.ljmu.qudexapps.xmllib.services;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader; //import java.net.FileNameMap;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;

import au.com.bytecode.opencsv.CSVReader;

import eu.medsea.mimeutil.MimeType;
import eu.medsea.mimeutil.MimeUtil;
import fedora.fedoraSystemDef.foxml.DatastreamType;
import uk.ljmu.metadata.schemas.SchemaInstance;
import uk.ljmu.metadata.schemas.SchemaInstanceContainer;
import uk.ljmu.metadata.schemasutilities.SchemasProcessing;
import uk.ljmu.metadata.utilities.MetadataUtilities;
import uk.ljmu.metadata.utilities.MetadataUtilities.ValueType;
import uk.ljmu.qudexapps.xmllib.exceptions.CSVException;
import uk.ljmu.qudexapps.xmllib.model.ColumnMap;
import uk.ljmu.qudexapps.xmllib.model.SpreadsheetMap;
import uk.ljmu.qudexapps.xmllib.utilities.Constants;
import uk.ljmu.qudexapps.xmllib.utilities.SpreadsheetUtilities;
import uk.ljmu.qudexapps.xmllib.utilities.SpreadsheetUtilities.Column;

/**
 * Implements the management interface for CSV spreadsheets
 * 
 * @author agustinamartinez
 * 
 */
public class CsvManagementImpl implements SpreadsheetManagement {
    private static Logger log = Logger.getLogger(CsvManagementImpl.class);
    /**
     * boolean specifying the spreadsheet type: qudex or normal objects
     * spreadsheet
     */
    private boolean qudexSS = false;
    
    private boolean qudexCollection;

    /**
     * Default ID header - must be present in the spreadsheet
     */
    private static final String PID_HEADER = "pid";
    /**
     * Compatibility with Exhibit - LABEL header must be present
     */
    private static final String LABEL_HEADER = "label";

    /**
     * Map structure to store the spreadsheet contents
     */
    private SpreadsheetMap mappingReader;
    /**
     * 
     */
    private SchemaInstanceContainer siContainer;

    /**
     * @param qudexCollection the qudexCollection to set
     */
    public void setQudexCollection(boolean qudexCollection) {
	this.qudexCollection = qudexCollection;
    }

    /**
     * @return the qudexCollection
     */
    public boolean isQudexCollection() {
	return qudexCollection;
    }

    /**
     * @param qudexSS
     *            the qudexSS to set
     */
    public void setQudexSS(boolean qudexSS) {
	this.qudexSS = qudexSS;
    }

    /**
     * @return the qudexSS
     */
    public boolean isQudexSS() {
	return qudexSS;
    }

    /**
     * @param siContainer
     *            the siContainer to set
     */
    public void setSiContainer(SchemaInstanceContainer siContainer) {
	this.siContainer = siContainer;
    }

    /**
     * @return the siContainer
     */
    public SchemaInstanceContainer getSiContainer() {
	return siContainer;
    }

    public SpreadsheetMap getSpreadsheetMap() {
	return mappingReader;
    }

    public CsvManagementImpl() {
	mappingReader = new SpreadsheetMap();
	siContainer = new SchemaInstanceContainer();
	qudexSS = false;
    }

    public CsvManagementImpl(boolean isQudexSS, boolean qCollection) {
	mappingReader = new SpreadsheetMap();
	siContainer = new SchemaInstanceContainer();
	qudexSS = isQudexSS;
	qudexCollection = qCollection;
    }

    /**
     * Read an Excel spreadsheet containing the information of the datastreams
     * to ingest into Fedora for one object Validation over ContentModelObject
     * performed if necessary
     * 
     * @param inputStream
     *            spreadsheet contents
     * @param container
     * @throws CSVException
     * @throws IOException
     */
    @SuppressWarnings("unchecked")
    public boolean readSpreadsheet(InputStream inputStream)
	    throws CSVException, IOException {

	CSVReader reader = null;
	List<?> myEntries;
	long iniTime = 0;

	try {
	    if (inputStream == null) {
		log.fatal("Null spreadsheet");
		throw new CSVException("Null Spreadsheet...");
	    }
	    try {
		reader = new CSVReader(new InputStreamReader(inputStream));
		myEntries = reader.readAll();
	    } catch (IOException e) {
		throw new CSVException(
			"In 'read' method: unable to create CSV spreadsheet");
	    }

	    int firstRow = 0;
	    int lastRow = myEntries.size() - 1;

	    // Check if empty spreadsheet
	    if (lastRow < 0) {
		throw new CSVException("The uploaded spreadsheet is empty.");
	    }
	    // Define column indexes
	    List<Column> columns = new ArrayList<Column>();
	    int r = firstRow;
	    int idColumn = -1;
	    int elementsSkipped = 0;

	    log.info("Parsing header columns...");
	    // AMG- New SchemaInstance Parser under testing
	    String[] headersRow = (String[]) myEntries.get(r);
	    int fCell = 0;
	    int lCell = headersRow.length;
	    List<String> headersArray = new ArrayList<String>();
	    for (int i = fCell; i < lCell; i++) {
		// SKIP DATASTREAM HEADERS
		String header = headersRow[i];
		if (this.isDatastreamHeader(header))
		    continue;
		headersArray.add(header);
	    }
	    // TEST NEW SCHEMA PARSER AMG
	    boolean headersParse = siContainer
		    .initialiseSchemasInstanceContainer(headersArray);
	    if (!headersParse) {
		log.fatal("Error while parsing metadata schema headers...");
		throw new CSVException(
			"Error while parsing metadata schema headers...");
	    }
	    try {
		for (; r <= lastRow; r++) {
		    String[] row = (String[]) myEntries.get(r);
		    if (row == null) {
			continue;
		    }

		    short firstCell = 0;
		    short lastCell = (short) (row.length - 1);

		    if (firstCell >= 0 && firstCell <= lastCell) {
			for (short c = 0; c <= lastCell; c++) {
			    String cell = row[c];
			    Column column = null;
			    if (cell != null) {
				String headerName = cell;
				if (headerName.length() > 0) {
				    column = new Column();
				    column.setColumnIndex(Integer.valueOf(c));
				    int colon = headerName.indexOf(':');
				    if (colon < 0) {
					column.setColumnName(headerName); // AMG-
					// NO
					// PREFIX
				    } else {
					column.setColumnName(headerName
						.substring(0, colon).trim());
					iniTime = System
						    .currentTimeMillis();
					// AMG- Check if it's a known metadata
					// schema
					boolean schemaAdded = this.findSchema(
						siContainer, headerName);
					log.info("Exec time _findSchema: "
							    + SpreadsheetUtilities
								    .getElapsedTimeHoursMinutesSecondsString(System
									    .currentTimeMillis()
									    - iniTime));
					if (schemaAdded) {
					    // AMG- Column name without the
					    // prefix
					    column
						    .setColumnName(headerName
							    .substring(
								    colon + 1,
								    headerName
									    .length()));
					    String prefix = headerName
						    .substring(0, colon);
					    column
						    .setColumnType(MetadataUtilities.MDSchemas
							    .get(prefix));
					} else {
					    // Normal header but with TYPE
					    // specifier
					    String columnType = headerName
						    .substring(colon + 1);
					    ValueType vType = this
						    .getColumTypeFromPrefix(columnType);
					    // AMG- Column not found: IGNORE
					    if (vType == null)
						continue;
					    column.setColumnName(headerName
						    .substring(0, colon));
					    column.setColumnType(vType);
					}
				    }
				    // AMG- If non qudex ss only, look for
				    // unique mandatory field
				    if (column.getColumnName()
					    .equalsIgnoreCase(PID_HEADER)
					    || column.getColumnName()
						    .equalsIgnoreCase(
							    LABEL_HEADER)) {
					if (qudexSS
						&& column.getColumnName()
							.equalsIgnoreCase(
								PID_HEADER)
						&& !qudexCollection) {
					    elementsSkipped++;
					    continue;
					}
					if (column.getColumnName()
						.equalsIgnoreCase(PID_HEADER))
					    idColumn = c;
				    }
				}
			    }
			    columns.add(column);
			}
			r++;
			break;
		    }
		}
	    } catch (Exception ex) {
		log.fatal(ex.getMessage());
		throw new CSVException(
			"Errors occurred while parsing the HEADERS of the spreadsheet.");
	    }

	    // Check if we've found all the mandatory headers
	    mappingReader.setGlobalMap(new LinkedHashMap<String, ColumnMap>());
	    // AMG- Check only for non qudes ss
	    if (!qudexSS) {
		if (idColumn < 0) {
		    throw new CSVException(
			    "ID or LABEL header not found in the spreadsheet. This header is mandatory.");
		}
	    }
	    /*
	     * The first pass will collect all the items and their properties as
	     * well as assign URIs to them.
	     */
	    log.info("Parsing spreadsheet rows...");
	    try {
		for (; r <= lastRow; r++) {
		    String[] row = (String[]) myEntries.get(r);
		    if (row == null) {
			continue;
		    }

		    short firstCell = 0;
		    short lastCell = (short) (row.length - 1 - elementsSkipped);
		    if (firstCell >= 0 && firstCell <= lastCell) {
			String cell;
			ColumnMap item;
			if (!qudexSS || qudexCollection) {
			    
			    if (qudexCollection && (idColumn < 0)) {
				 // AMG- for qudex ss we generate a unique identifier
				    // for each row since PID column is not present
				    UUID uuid = UUID.randomUUID();
				    item = new ColumnMap(String.class.getName());
				    item.setIdentifier(uuid.toString());
				    mappingReader.getGlobalMap().put(uuid.toString(),
					    item);
			    } else {
				cell = row[idColumn];
				if (cell == null || cell.equals("")) {
				    if (qudexCollection) {
					UUID uuid = UUID.randomUUID();
					cell = uuid.toString();
				    } else continue;
				}

				item = new ColumnMap(String.class.getName());
				item.setIdentifier(cell);
				mappingReader.getGlobalMap().put(cell, item);
			    }
			} else {
			    // AMG- for qudex ss we generate a unique identifier
			    // for each row since PID column is not present
			    UUID uuid = UUID.randomUUID();
			    item = new ColumnMap(String.class.getName());
			    item.setIdentifier(uuid.toString());
			    mappingReader.getGlobalMap().put(uuid.toString(),
				    item);
			}
			for (short c = 0; c <= lastCell; c++) {
			    SpreadsheetUtilities.Column column = columns.get(c);

			    if (column != null) {
				cell = row[column.getColumnIndex()];
				// CHECK WHAT OTHER VALIDATIONS
				if (cell.length() != 0) {
				    ((Map<SpreadsheetUtilities.Column, String>) item
					    .getColumnMap()).put(column,
					    (String) cell);
				}
			    }
			}
		    }
		}
	    } catch (Exception ex) {
		log.fatal(ex.getMessage());
		throw new CSVException(
			"Errors occurred while parsing the CONTENTS of the spreadsheet.");
	    }
	    log.info("Finished parsing spreadsheet...");
	    return true;
	} finally {
	    if (inputStream != null)
		inputStream.close();
	    if (reader != null)
		reader.close();
	}
    }

    public String getCellString(Object cell) {
	return (String) cell;
    }

    public String returnStringCellContent(Object cell) {
	return (String) cell;
    }

    /**
     * 
     * @param identifier
     * @param elementsPresent
     * @return XML string containing the RELS-EXT datastream contents
     */
    public String constructFedoraRelationshipsTemplate(String identifier,
	    String objectPID, boolean elementsPresent) {
	// Create document
	Element root = DocumentHelper.createElement("rdf:RDF");
	root.addNamespace("rdf", MetadataUtilities.RELS_MAP.get("rdf"));
	root.addNamespace("fedora-model", MetadataUtilities.RELS_MAP
		.get("fedora-model"));
	root.addNamespace("rel", MetadataUtilities.RELS_MAP.get("rel"));
	Element description = DocumentHelper.createElement("rdf:Description");
	description.addAttribute("rdf:about",
		!objectPID.startsWith("info") ? MetadataUtilities.OBJECTID
			+ objectPID : objectPID);
	root.add(description);
	Document doc = DocumentHelper.createDocument(root);

	if (elementsPresent) {
	    ColumnMap item;
	    item = this.getSpreadsheetMap().getGlobalMap().get(identifier);
	    String str = "";
	    for (Column column : item.getColumnMap().keySet()) {
		// AMG - Now has to manage also rdf:type element which indicate
		// whether the object is a
		// collection or NOT - Not using dc:type anymore
		if (column.getColumnType().equals(
			MetadataUtilities.ValueType.RELS_EXT)
			|| (column.getColumnType().equals(
				MetadataUtilities.ValueType.RdfElement) && column
				.getColumnName().equalsIgnoreCase("type"))) {
		    String qualifiedName = "";

		    if (column.getColumnType().equals(
			    MetadataUtilities.ValueType.RELS_EXT))
			qualifiedName = "rel:" + column.getColumnName();
		    else
			qualifiedName = column.getColumnName();

		    String cell = (String) item.getColumnMap().get(column);
		    Element elem = DocumentHelper.createElement(qualifiedName);

		    // Check if we have a list of values
		    String cellValue = this
			    .returnStringCellContent((String) cell);
		    // TODO Check all the split(';') and add the trim() call
		    String[] listValues = cellValue.trim().split(
			    Constants.FIELDS_SEPARATOR);

		    if (listValues.length > 1) {
			for (String strValue : listValues) {
			    if (column.getColumnType().equals(
				    MetadataUtilities.ValueType.RELS_EXT)) {
				if (!strValue
					.startsWith(MetadataUtilities.OBJECTID))
				    str = MetadataUtilities.OBJECTID + strValue;
				elem.addAttribute("rdf:resource",
					(str != "") ? str : strValue);
				str = "";
				description.add(elem);
				elem = DocumentHelper
					.createElement(qualifiedName);
			    } else {
				// AMG - Manage rdf:type collection element
				if (column.getColumnType().equals(
					MetadataUtilities.ValueType.RdfElement)
					&& column.getColumnName()
						.equalsIgnoreCase("type")) {
				    // if (!strValue.contains("rdf"))
				    // str =
				    // MetadataUtilities.MDSchemasUrl.get("dcmitype")
				    // + strValue;

				    // AMG - MANAGE THIS
				    if (!SchemasProcessing
					    .checkValidURI(strValue)) {
					if (SchemasProcessing
						.isPartOfDCMI(strValue)) {
					    if (!cellValue.startsWith("http"))
						str = MetadataUtilities.MDSchemasUrl
							.get("dcmitype")
							+ strValue;
					} else {
					    // AMG - We skip it, bad formed
					    // element
					    continue;
					}
				    }
				    elem.setQName(new QName("rdf:"
					    + column.getColumnName()));
				    elem.addAttribute("rdf:resource",
					    (str != "") ? str : strValue);
				    str = "";
				    description.add(elem);
				    elem = DocumentHelper.createElement(column
					    .getColumnName());
				}
			    }
			}
		    } else {
			if (column.getColumnType().equals(
				MetadataUtilities.ValueType.RELS_EXT)) {
			    if (!cellValue
				    .startsWith(MetadataUtilities.OBJECTID))
				str = MetadataUtilities.OBJECTID + cellValue;
			    elem.addAttribute("rdf:resource", (str != "") ? str
				    : cellValue);
			    str = "";
			    description.add(elem);
			    elem = DocumentHelper.createElement(qualifiedName);
			} else {
			    // AMG - Manage rdf:type collection element
			    if (column.getColumnType().equals(
				    MetadataUtilities.ValueType.RdfElement)
				    && column.getColumnName().equalsIgnoreCase(
					    "type")) {
				// if (!cellValue.contains("rdf"))
				// str =
				// MetadataUtilities.MDSchemasUrl.get("dcmitype")
				// + cellValue;
				// AMG - MANAGE THIS
				if (!SchemasProcessing.checkValidURI(cellValue)) {
				    if (SchemasProcessing
					    .isPartOfDCMI(cellValue)) {
					if (!cellValue.startsWith("http"))
					    str = MetadataUtilities.MDSchemasUrl
						    .get("dcmitype")
						    + cellValue;
				    } else {
					// AMG - We skip it, bad formed element
					continue;
				    }
				}
				elem.setQName(new QName("rdf:"
					+ column.getColumnName()));
				elem.addAttribute("rdf:resource",
					(str != "") ? str : cellValue);
				str = "";
				description.add(elem);
				elem = DocumentHelper.createElement(column
					.getColumnName());
			    }
			}
		    }

		}
	    }
	}

	return doc.asXML();
    }

    /**
     * Method to create a RDF-XML RELS-EXT datastream object
     * 
     * @param objectPID
     *            PID of the object being referenced
     * @param propertyIdentifier
     *            property to be added
     * @param propertyValue
     *            property value
     * 
     * @return string XML contents of the datastream object
     */
    public String constructFerodaRelationshipsTemplate(String objectPID,
	    String propertyIdentifier, String propertyValue) {
	// Create document
	String str = "";

	Element root = DocumentHelper.createElement("rdf:RDF");
	root.addNamespace("rdf", MetadataUtilities.RELS_MAP.get("rdf"));
	root.addNamespace("fedora-model", MetadataUtilities.RELS_MAP
		.get("fedora-model"));
	root.addNamespace("rel", MetadataUtilities.RELS_MAP.get("rel"));
	Element description = DocumentHelper.createElement("rdf:Description");
	if (!objectPID.startsWith("info"))
	    str = MetadataUtilities.OBJECTID + objectPID;
	description.addAttribute("rdf:about", str != "" ? str : objectPID);
	str = "";
	root.add(description);
	Document doc = DocumentHelper.createDocument(root);

	Element elem = DocumentHelper.createElement(propertyIdentifier);
	if (!propertyValue.startsWith("info"))
	    str = MetadataUtilities.OBJECTID + propertyValue;
	elem.addAttribute("rdf:resource", str != "" ? str : propertyValue);
	description.add(elem);

	return doc.asXML();
    }

    public SchemaInstanceContainer getSchemaInstanceContainer() {
	return siContainer;
    }

    /**
     * Iterates to the map of elements from the datastreams spreadsheet to find
     * any column storing DC values, RELS-EXT values, other schemas
     * 
     * @return true if found DC element, otherwise false
     */
    public boolean hasFields(SpreadsheetMap mappingReader,
	    MetadataUtilities.ValueType value) {
	for (ColumnMap item : mappingReader.getGlobalMap().values()) {
	    for (Column column : item.getColumnMap().keySet()) {
		if (column.getColumnType().equals(value)
			|| (value.equals(MetadataUtilities.ValueType.RELS_EXT) && column
				.getColumnType().equals(
					MetadataUtilities.ValueType.RdfElement)))
		    return true;
	    }
	}
	return false;
    }

    /**
     * Obtains the mimetype of a file either by its path or URL
     * 
     * @param type
     *            1 for file path, for URL other
     * @param path
     *            file path or file URL
     * @return string mimetype of the input file
     * @throws IOException
     */
    public String getMimeType(int type, String path) throws IOException {

	if (type == 1) {
	    // FILE
	    File f = new File(path);
	    MimeUtil
		    .registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
	    Collection<?> mimeTypes = MimeUtil.getMimeTypes(f);
	    if (!mimeTypes.isEmpty()) {
		MimeType mtype = (MimeType) mimeTypes.iterator().next();
		return mtype.toString();
	    } else
		return "";
	} else {
	    // FileNameMap fileNameMap = URLConnection.getFileNameMap();
	    // String typeFile = fileNameMap.getContentTypeFor(path);
	    // return typeFile;
	    URL u = new URL(path);
	    URLConnection uc = null;
	    uc = u.openConnection();
	    String typeFile = uc.getContentType();

	    return typeFile;
	}
    }

    public boolean isDatastreamHeader(String header) {
	String[] splitHeader = header.split(":");

	if (splitHeader.length < 2) {
	    return false;
	}
	if (splitHeader[1].equalsIgnoreCase(DatastreamType.CONTROLGROUP.X
		.toString())
		|| header.equalsIgnoreCase(DatastreamType.CONTROLGROUP.M
			.toString())
		|| header.equalsIgnoreCase(DatastreamType.CONTROLGROUP.E
			.toString())
		|| header.equalsIgnoreCase(DatastreamType.CONTROLGROUP.R
			.toString()) || header.equalsIgnoreCase(PID_HEADER))
	    return true;
	else
	    return false;
    }

    // UTILITIES FOR PARSING SPECIFIC PARTS: DC SCHEMA, RELS_-EXT DS's, OTHERS
    /**
     * For a given object returns the XML string of the DC or RELS-EXT elements,
     * if present for that object
     * 
     * @param utils
     * @param identifier
     *            key identifier for the item in the map
     * @param typeValidation
     *            ValueType item specifying the schema to validate
     * @return string containing the XML DC document, otherwise ""
     */
    public String constructDocument(String identifier,
	    MetadataUtilities.ValueType typeValidation, String objectPID) {
	boolean hasElements = false;

	hasElements = this.hasFields(this.getSpreadsheetMap(), typeValidation);

	if (hasElements) {
	    String results = "";

	    if (typeValidation.equals(MetadataUtilities.ValueType.DcElement)) {
		results = constructDublincoreTemplate(identifier);
	    } else if (typeValidation
		    .equals(MetadataUtilities.ValueType.RELS_EXT)) {
		results = constructFedoraRelationshipsTemplate(identifier,
			objectPID, true);
	    }

	    return results;
	}
	// No DC elements
	return "";
    }

    /**
     * 
     * @param utils
     * @param identifier
     * @return XML string containing the DC datastream contents
     */
    public String constructDublincoreTemplate(String identifier) {
	// Create document
	Element root = DocumentHelper.createElement("oai_dc:dc");
	root.addNamespace("oai_dc", MetadataUtilities.RELS_MAP.get("oai_dc"));
	root.addNamespace("dc", MetadataUtilities.RELS_MAP.get("dc"));
	Document doc = DocumentHelper.createDocument(root);

	ColumnMap item;

	item = this.getSpreadsheetMap().getGlobalMap().get(identifier);
	// Caught Null pointer exception
	if (item == null)
	    return "";
	for (Column column : item.getColumnMap().keySet()) {
	    if (column.getColumnType().equals(
		    MetadataUtilities.ValueType.DcElement)) {
		Element element = DocumentHelper.createElement(column
			.getColumnName());
		String cell = (String) item.getColumnMap().get(column);
		element.setText(this.returnStringCellContent(cell));

		root.add(element);
	    }
	}
	return doc.asXML();
    }

    public String getCellContent(Object item, Object col) {
	String value = "";
	try {
	    value = (String) ((ColumnMap) item).getColumnMap().get((Column) col);
	} catch (Exception ex) {
	    log.fatal(ex.getMessage());
	}
	return value;
    }

    // PRIVATE METHODS
    private boolean findSchema(SchemaInstanceContainer schemasContainer,
	    String elementName) throws CSVException {
	boolean enc = false;

	// EXTRACT PREFIX
	int index = elementName.indexOf(":");
	if (index < 0)
	    throw new CSVException("Schema element name not well formed");
	String prefix = elementName.substring(0, index);
	String name = elementName.substring(index + 1, elementName.length());

	for (SchemaInstance schemaIns : schemasContainer
		.getListSchemaInstances()) {
	    if (schemaIns.getSchemaPrefix().equalsIgnoreCase(prefix)) {
		// NEW SCHEMA PARSER
		enc = schemasContainer.addMetadataElementToSchemaInstance(
			prefix, schemaIns.getSchemaURI(), name);
		if (!enc) {
		    // ELEMENT NOT PRESENT IN THE GIVEN SCHEMA
		    throw new CSVException(
			    "In findSchema method, schema element header ("
				    + prefix + ":" + name
				    + ") not present in the given schema");
		}
	    }
	}
	return enc;
    }

    /**
     * @param columnPrefix
     */
    private ValueType getColumTypeFromPrefix(String columnPrefix) {
	if (columnPrefix
		.equalsIgnoreCase(MetadataUtilities.FEDORA_RELATIONS_NS_PREFIX))
	    return ValueType.RELS_EXT;
	else if (columnPrefix.equalsIgnoreCase(ValueType.Number.toString()))
	    return ValueType.Number;
	else if (columnPrefix.equalsIgnoreCase(ValueType.Boolean.toString()))
	    return ValueType.Boolean;
	else if (columnPrefix.equalsIgnoreCase(ValueType.URL.toString()))
	    return ValueType.URL;
	else if (columnPrefix.equalsIgnoreCase(ValueType.X.toString())) {
	    return ValueType.X;
	} else if (columnPrefix.equalsIgnoreCase(ValueType.E.toString())) {
	    return ValueType.E;
	} else if (columnPrefix.equalsIgnoreCase(ValueType.M.toString())) {
	    return ValueType.M;
	} else if (columnPrefix.equalsIgnoreCase(ValueType.R.toString())) {
	    return ValueType.R;
	}
	// AMG- No matching found
	log
		    .info("getColumTypeFromPrefix, parsing spreadsheet no valuetype matching...: "
			    + columnPrefix);
	return null;
    }

    public void cleanInstance() {
	this.siContainer.getListSchemaInstances().clear();
	this.mappingReader.getGlobalMap().clear();
    }

    /**
     * 
     * @return
     */
    public Object getPidFromSpreadsheet(Object cmap) {
	String pid = "";

	for (Column col : ((ColumnMap) cmap).getColumnMap().keySet()) {
	    if (col.getColumnName().equalsIgnoreCase(PID_HEADER)) {
		pid = returnStringCellContent((String) ((ColumnMap) cmap).getColumnMap().get(
			col));
		break;
	    }
	}
	return pid;
    }
    /**
     * @param rowIdentifier
     * @param columnIdentifier
     */
    public Object getColumnByIdentifier(Object rowIdentifier, Object columnIdentifier) {
	
	if (this.mappingReader.getGlobalMap().containsKey(rowIdentifier)) {
	    ColumnMap colMap = this.mappingReader.getGlobalMap().get(rowIdentifier);
	    for (Column column : colMap.getColumnMap().keySet()) {
		    if (column.getColumnName().equals(columnIdentifier)) {
			return column;
		    }
		}
	}
	//NOT found
	log.info("Column with id: " + columnIdentifier + " not found in Spreadsheet.");
	return null;
    }
    /**
     * Returns the Column Map for a given spreadsheet row
     * 
     * @param rowIdentifer row identifier string to look for
     * 
     * @return Column Map for the given row, if found, null otherwise
     */
    public Object getColumnMap(Object rowIdentifier) {
	if (this.mappingReader.getGlobalMap().containsKey(rowIdentifier)) {
	    return this.mappingReader.getGlobalMap().get(rowIdentifier).getColumnMap();
	}
	//Not found
	log.info("Row wit identifier: " + rowIdentifier + " not found");
	return null;
    }

    public Object getRowColumnValue(Object rowIdentifier, Object columnId) {
	Column col = (Column) this.getColumnByIdentifier(rowIdentifier, columnId);
	Map<Column, ?> map = this.mappingReader.globalMap.get(rowIdentifier).getColumnMap();
	if (col != null && map != null)
	    return this.returnStringCellContent(map.get(col));
	else return null;
    }
}
